package backend

import (
	"context"
	"slapp3/backend/application/controller"
	"slapp3/backend/application/domain"
	"slapp3/backend/application/repository"
	"slapp3/backend/application/service"
	"slapp3/backend/config"
	"slapp3/backend/logger"
	ssllink "slapp3/backend/sslink"

	"github.com/wailsapp/wails/v3/pkg/application"
	"github.com/wailsapp/wails/v3/pkg/services/notifications"
	"go.uber.org/zap"
)

// App struct
type App struct {
	ctx            context.Context
	log            *zap.Logger
	config         *config.Config
	connectService *service.ConnectService
	cancel         func()
	ssllink        controller.SslinkRepository
	notifier       *notifications.NotificationService
	Version        string
}

// NewApp creates a new App application struct
func NewApp(version string) *App {
	app := &App{
		Version: version,
	}
	app.notifier = notifications.New()
	return app
}

// startup is called when the app starts. The context is saved
// so we can call the runtime methods
func (a *App) ServiceStartup(ctx context.Context, options application.ServiceOptions) error {
	var err error
	a.ctx = ctx
	a.config = config.NewConfig()

	if a.config.Env == "production" {
		a.log = logger.NewProductionLogger(a.config.Log.Path)
	} else {
		a.log = logger.NewDevelopmentLogger(a.config.Log.Path)
	}
	data, cancel, err := repository.NewData(a.config, a.log)
	if err != nil {
		a.log.Fatal("Failed to initialize data", zap.Error(err))
		return err
	}

	a.ssllink = ssllink.NewSslink(a.log, a.config)

	connRepo := repository.NewConnectRepository(data)
	connController := controller.NewConnectController(connRepo, a.ssllink)
	a.connectService = service.NewConnectService(a.ctx, a.config, connController)
	a.cancel = func() {
		if cancel != nil {
			cancel()
		}
	}

	a.log.Info("Application started", zap.String("env", a.config.Env), zap.String("logPath", a.config.Log.Path))

	return nil
}

func (a *App) Connect(id uint) bool {
	if err := a.connectService.Connect(id); err != nil {
		a.log.Error("Failed to connect", zap.Error(err))
		return false
	}
	return true
}

func (a *App) Disconnect() bool {
	if err := a.connectService.Disconnect(); err != nil {
		a.log.Error("Failed to disconnect", zap.Error(err))
		return false
	}
	return true
}

func (a *App) Shutdown(op ...interface{}) {
	if a.log != nil {
		a.log.Info("Application shutting down")
		a.log.Sync() // Ensure all logs are flushed
	}
	if a.cancel != nil {
		a.cancel()
	}
}

func (a *App) CreateConnect(profile domain.Profile) error {
	if err := a.connectService.CreateConnection(profile); err != nil {
		a.log.Error("Failed to create connection", zap.Error(err))
		return err
	}
	return nil
}

func (a *App) GetConnect(id uint) (domain.Profile, error) {
	profile, err := a.connectService.GetConnection(id)
	if err != nil {
		a.log.Error("Failed to get connection", zap.Error(err))
		return domain.Profile{}, err
	}
	return profile, nil
}

func (a *App) UpdateConnect(profile domain.Profile) error {
	if err := a.connectService.UpdateConnection(profile); err != nil {
		a.log.Error("Failed to update connection", zap.Error(err))
		return err
	}
	return nil
}

func (a *App) DeleteConnect(id uint) error {
	if err := a.connectService.DeleteConnection(id); err != nil {
		a.log.Error("Failed to delete connection", zap.Error(err))
		return err
	}
	return nil
}

func (a *App) ListConnects(page, pageSize int) ListConnectionsResp {
	profiles, total, err := a.connectService.ListConnections(page, pageSize)
	if err != nil {
		a.log.Error("Failed to list connections", zap.Error(err))
		return ListConnectionsResp{}
	}
	return ListConnectionsResp{Profiles: profiles, Total: total}
}

func TestConnect(version string) {
	config := config.NewConfig()
	log := logger.NewDevelopmentLogger(config.Log.Path)
	ssllink := ssllink.NewSslink(log, config)
	ssllink.SetProfile(&domain.Profile{
		Host:               "192.168.23.199:8080",
		Name:               "CES",
		Username:           "admin",
		Password:           "admin123",
		Group:              "admin",
		InsecureSkipVerify: true,
		NoDTLS:             true,
		Version:            version,
	})
	allowGroups, err := ssllink.InitAuth()
	if err != nil {
		log.Error("Failed to initialize auth", zap.Error(err))
		return
	}
	log.Info("Allowed groups:", zap.Strings("groups", allowGroups))
	if len(allowGroups) != 0 {
		// 请用户选择
		log.Info("Please select a group from the allowed groups", zap.Strings("groups", allowGroups))
		return
	}
	ssllink.PasswordAuth()
	ssllink.SetupTunnel()
}
